#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/ioctl.h> 
#include <locale.h>
#include <libintl.h>
#include <dirent.h>
#include <langinfo.h>
#include <term.h>
#include <ncurses.h>
#include <assert.h>
#include <sys/types.h>
#include <pwd.h>

struct shape
{
    char *first;        /* 0x00 */
    char *second;       /* 0x08 */
    char *three;        /* 0x10 */
    char *four;         /* 0x18 */
    char *five;         /* 0x20 */
    char *six;          /* 0x28 */
};

struct shape s_one = {
    "  ",
    "\033(0\017tq\033(B",
    "\033(0\017x\033(B ",
    "\033(0\017mq\033(B",
    "\033(0\017qqq\033(B",
    "\033(0\017qwq\033(B"
};

struct shape s_two = {
    .first  = "  ",
    .second = "├─",
    .three  = "│ ",
    .four   = "└─",
    .five   = "───",
    .six    = "─┬─"
};

struct shape s_three = {
    "  ",
    "|-",
    "| ",
    "`-",
    "---",
    "-+-"
};

struct shape *shape_pointer = &s_three;

/* Names for the values of the 'has_arg' field of 'struct option'.  */
# define no_argument            0
# define required_argument      1
# define optional_argument      2

static struct option const long_options[] =
{
	{"arguments", no_argument, NULL, 'a'},
	{"ascii", no_argument, NULL, 'A'},
	{"compact-not", no_argument, NULL, 'c'},
	{"color", 1, NULL, 'C'},
	{"vt100", no_argument, NULL, 'G'},
	{"highlight-all", no_argument, NULL, 'h'},
	{"highlight-pid", 1, NULL, 'H'},
	{"long", no_argument, NULL, 'l'},
	{"numeric-sort", no_argument, NULL, 'n'},
	{"ns-sort", 1, NULL, 'N'},
	{"show-pids", no_argument, NULL, 'p'},
	{"show-pgids", no_argument, NULL, 'g'},
	{"show-parents", no_argument, NULL, 's'},
	{"ns-changes", no_argument, NULL, 'S'},
	{"thread-names", no_argument, NULL, 't'},
	{"hide-threads", no_argument, NULL, 'T'},
	{"uid-changes", no_argument, NULL, 'u'},
	{"unicode", no_argument, NULL, 'U'},
	{"version", no_argument, NULL, 'V'},
	{"security-context", no_argument, NULL, 'Z'},
	{NULL, 0, NULL, 0}
};

char *gvar_8ba0[] = {
    [0] = "cgroup",
    [1] = "ipc",
    [2] = "mnt",
    [3] = "net",
    [4] = "pid",
    [5] = "user",
    [6] = "uts",
    [7] = "time"
};

#define COMM_LEN 64

typedef struct _proc {
    char comm[COMM_LEN + 2 + 1]; /* add another 2 for thread brackets */    // 72           // ==> 0x00
    char **argv;    // 8         /* only used : argv[0] is 1st arg; undef if argc < 1 */    // ==> 0x48
    int argc;       // 4         /* with -a   : number of arguments, -1 if swapped    */    // ==> 0x50
    pid_t pid;      // 4                // ==> 0x54
    pid_t pgid;     // 4                // ==> 0x58
    pid_t uid;      // 4                // ==> 0x5c
    ino_t ns[8];    // 64               // ==> 0x60
    char flags;     // 8                // ==> 0xA0
    double age;     // 8                // ==> 0xA8
    struct _child *children;    // 8    // ==> 0xB0
    struct _proc *parent;       // 8    // ==> 0xB8
    struct _proc *next;         // 8    // ==> 0xC0
} PROC;

typedef struct _child {
    PROC *child;                // ==> 0x00
    struct _child *next;        // ==> 0x08
} CHILD;

struct ns_entry {
    ino_t number;               // ==> 0x00
    CHILD *children;            // ==> 0x08
    struct ns_entry *next;      // ==> 0x10
};

struct age_to_color {
    unsigned int age_seconds;
    char *color;
};

struct age_to_color gvar_g2e0[] = {
    { 60, "\033[32m"},
    {3600,   "\033[33m"},
    {0,	    "\033[31m"}
};


int gvar_9468 = 0;
int gvar_6b20 = 0;
int gvar_6982 = 0;
int gvar_92c8 = 1;
int gvar_92c4 = 113;
int gvar_92cc = 1;
int gvar_9440 = 0;
int gvar_9444 = 0;
int gvar_9448 = 0;
int gvar_9450 = 0;
int gvar_9454 = 0;
int gvar_9458 = 0;
int gvar_945c = 0;
char *gvar_61cb = "/proc";
double gvar_6c70 = 0.0;
PROC *gvar_9488 = NULL;
int gvar_9438 = 0;
int *gvar_9478 = 0;
int *gvar_9470 = 0;
int gvar_9480 = 0;
int gvar_9430 = 0;
int gvar_9400 = 0;
int gvar_9460 = 0;
int gvar_9464 = 0;
int gvar_944c = 0;
int gvar_92c0 = 0;
int gvar_943c = 0;
int gvar_9434 = 0;


void fun_3bd0_help();
void fun_5460();
int get_ws_col();
int fun_4f20(PROC *a, PROC * b);
static PROC *fun_4fd0(const char *comm, pid_t pid, uid_t uid);
int fun_5150(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
         const char *args, int size, char isthread, double process_age_sec);
int fun_4110(char *str);
void fun_4340(PROC * current, int level, int rep, int leaf, int last,
          uid_t prev_uid, int closing);
void trim_tree_by_parent(PROC *a);
static void fun_3db0(PROC *r, int id, struct ns_entry **root);
void fun_3f90(const char str);
int fun_4060(int x);
void fun_4210(void);
int fun_4270(const PROC * a, const PROC * b);
void fun_4e70(PROC * current, uid_t uid);
static void out_string(const char *str);
static PROC *find_proc(pid_t pid);

void fun_4e70(PROC * current, uid_t uid)  // dump_by_user
{
    const CHILD *walk;

    if (current == NULL) {
        return;
    }

    if (current->uid == uid) {
        // je 4eb8
        if (gvar_9438) {
            // jne 4f00 --> jmp 4ec2
            putchar(0xa);
        }

        fun_4340(current, 0, 1, 1, 1, uid, 0);
        gvar_9438 = 1;

        return;
    }

    for (walk = current->children; walk; walk = walk->next) {
        fun_4e70(walk->child, uid);
    }
}

int fun_4270(const PROC * a, const PROC * b)
{
    const CHILD *walk_a, *walk_b;
    int i;

    if (strcmp(a->comm, b->comm) != 0) {
        return 0;
    }

    if (gvar_9464 && a->uid != b->uid) {
        return 0;
    }

    if (gvar_944c) {
        for (i = 0; i < 0x7; i++)
            if (a->ns[i] != b->ns[i])
                return 0;
    }

    for (walk_a = a->children, walk_b = b->children; walk_a && walk_b;
         walk_a = walk_a->next, walk_b = walk_b->next) {
        if (fun_4270(walk_a->child, walk_b->child) == 0) {
            // je 4302
            return 0;
        }
    }

    return !(walk_a || walk_b);
}

void fun_4210(void)
{
    if (gvar_943c && gvar_92c0 == gvar_92c4) {
        // je 4258
        putchar(gvar_943c);
    }
    gvar_943c = 0x0;
    putchar(0xa);
    gvar_92c0 = 1;
}

int fun_4060(int x)
{
    int digits, div;
    if (x != 0) {
        digits = 0;
        for (div = 1; x / div; div *= 10)
            digits++;
        for (div /= 10; div; div /= 10)
            fun_3f90('0' + (x / div) % 10);
        return digits;
    }
    
    return 0x1;
}

int fun_4110(char *str)
{
    char *here;
    int count = 0;
    char temp[5] = {0};

    for (here = str; *here; here++) {
        if (*here == '\\') {
            out_string("\\\\");
            count += 2;
        }
        else if (*here >= ' ' && *here <= '~') {
            // jbe 4140
            fun_3f90(*here);
            count++;
        }
        else {
            sprintf(temp, "\\%03o", (unsigned char) *here);
            // __sprintf_chk(temp, 1, 5, "\\%03o", (unsigned char) *here);
            out_string(temp);
            count += 4;
        }
    }

    return count;
}

void fun_3bd0_help()
{
    fprintf(stderr, "%s", "Usage: pstree [-acglpsStTuZ] [ -h | -H PID ] [ -n | -N type ]\n   [ -A | -G | -U ] [ PID | USER ]\n   or: pstree -V\n");
    fprintf(stderr, "%s", "\nDisplay a tree of processes.\n\n");
    fprintf(stderr, "%s", "  -a, --arguments     show command line arguments\n  -A, --ascii         use ASCII line drawing characters\n  -c, --compact-not   don't compact identical subtrees\n");
    fprintf(stderr, "%s", "  -C, --color=TYPE    color process by attribute\n    (age)\n");
    fprintf(stderr, "%s", "  -g, --show-pgids    show process group ids; implies -c\n  -G, --vt100         use VT100 line drawing characters\n");
    fprintf(stderr, "%s", "  -h, --highlight-all highlight current process and its ancestors\n  -H PID, --highlight-pid=PID\n highlight this process and its ancestors\n  -l, --long          don't truncate long lines\n");
    fprintf(stderr, "%s", "  -n, --numeric-sort  sort output by PID\n  -N TYPE, --ns-sort=TYPE\n sort output by this namespace type\n cgroup, ipc, mnt, net, pid, user, uts)\n  -p, --show-pids     show PIDs; implies -c\n");
    fprintf(stderr, "%s", "  -s, --show-parents  show parents of the selected process\n  -S, --ns-changes    show namespace transitions\n  -t, --thread-names  show full thread names\n  -T, --hide-threads  hide threads, show only processes\n");
    fprintf(stderr, "%s", "  -u, --uid-changes   show uid transitions\n  -U, --unicode       use UTF-8 (Unicode) line drawing characters\n  -V, --version       display version information\n");
    fprintf(stderr, "%s", "  -Z, --security-context\n show SELinux security contexts\n");
    fprintf(stderr, "%s", "\n  PID    start at this PID; default is 1 (init)\n  USER   show only trees rooted at processes of this user\n\n");
}

void fun_5460()
{
    fprintf(stderr, "%s", "UNKNOWN");
    fprintf(stderr, "%s", "Copyright (C) 1993-2019 Werner Almesberger and Craig Small\n\n");
    fprintf(stderr, "%s", "PSmisc comes with ABSOLUTELY NO WARRANTY.\nThis is free software, and you are welcome to redistribute it under\nthe terms of the GNU General Public License.\nFor more information about these matters, see the files named COPYING.\n");
}

void fun_3f90(const char ch)
{
    if (gvar_9434 == 0) {
        // 3fe0
        if ((ch & 0xe0) == 0xc0) {
            gvar_9434 = 1;
        } else if ((ch & 0xf0) == 0xe0) {
            gvar_9434 = 2;
        } else if ((ch & 0xf8) == 0xf0) {
            gvar_9434 = 3;
        } else {
            gvar_9434 = 1;
        }

        gvar_92c0++;
    }

    gvar_9434 -= 1;

    if (gvar_92c8 == 0 || gvar_92c0 <= gvar_92c4) {
        // je 3fc8
        // jle 3fc8
        putchar(ch);
    }
    else if (gvar_92c8 != 0 && gvar_92c0 == gvar_92c4 + 1) {
        // je 4040
        putchar('+');            
    }
}

static void out_string(const char *str)
{
    while (*str)
        fun_3f90(*str++);
}

void fun_4340(PROC * current, int level, int rep, int leaf, int last,
          uid_t prev_uid, int closing)
{
    CHILD *walk, *next, *tmp_child, **scan;
    const struct passwd *pw;
    int lvl, i, add, len, swapped, info, count, comm_len, first;
    const char *tmp, *here;

    assert(closing >= 0);

    if (current == NULL)
        return;

    if (leaf == 0) {
        for (lvl = 0; lvl < level; lvl++) {
            for (i = gvar_9478[lvl] + 1; i; i--)
                fun_3f90(' ');
            out_string(lvl == level - 1 ? last ? shape_pointer->four : shape_pointer->second : gvar_9470[lvl + 1] ?
                       shape_pointer->three : shape_pointer->first);
            }
    }

    add = 0;
    if (rep > 1) {
        // jg 491a
        add = fun_4060(rep) + 2;
        out_string("*[");
    }

    if (gvar_9430 == 1) {
        // je 4958
        struct age_to_color *p;
        for(p = gvar_g2e0; p->age_seconds != 0; p++) {
            // jae 4978
            if (current->age < p->age_seconds)
                break;
        }

        char *strp = p->color;
        while (*strp) {
            fun_3f90(*strp++);
        }
    }

    if ((current->flags & 0x1) && (tmp=tgetstr("md", NULL))) {
        // jne 49c1
        tputs(tmp, 1, putchar);
        // jmpq   4449
    }
    else if (current->flags  & 0x1 && (tmp=tgetstr("md", NULL))) {
        // je 4449
        // 此分支可以省略
    }

    swapped = info = gvar_9468;

    if (gvar_9468 && current->argc < 0) {
        // js 4db8
        fun_3f90('(');
        // jmpq 4463
    }

    comm_len = fun_4110(current->comm);
    rep = gvar_92c0;

    if (gvar_9460 != 0) {
        fun_3f90(',');
        (void) fun_4060(current->pid);
    }

    if (gvar_945c != 0) {
        // jne 4d78 -> 4d05 -> 44b0
        // jmpq 4d10 -> 44b0
        if (info == 0) {
            // je 4d05
            fun_3f90('(');
            fun_4060(current->pgid);
            // jmpq  44b0
        }
        fun_3f90(',');
        fun_4060(current->pgid);
        // jmpq  44b0
    }

    if (gvar_9464 && prev_uid != current->uid) {
        fun_3f90(',');
        if ((pw = getpwuid(current->uid))) {    
            out_string(pw->pw_name);
            info++;
        } 
        else {
            // je 4de4
            fun_4060(current->uid);
            // jmpq 4517
        }
    }

    if (gvar_944c && current->parent) {
        for (i = 0; i < 0x7; i++) {
            if (current->ns[i] == 0 || current->ns[i] == current->parent->ns[i] || current->parent->ns[i] == 0) {
                continue;
            }

            fun_3f90(info++ ? ',' : '(');
            out_string(gvar_8ba0[i]);
        }
    }

    if (gvar_9440) {
        fun_3f90(info++ ? ',' : '(');
        out_string("`");
        fun_3f90(current->ns[0] ? '`' : '\\');       // ????
    }

    if ((swapped && gvar_9468 && current->argc < 0) || (!swapped && info))
        fun_3f90(')');

    if ((current->flags & 0x01) && (tmp = tgetstr("me", NULL)))
        tputs(tmp, 1, putchar);

    if (gvar_9468) {
        // jne 4a2d
        for (i = 0; i < current->argc; i++) {
            if (i < current->argc - 1) {
                // jg 4ac4
                fun_3f90(' ');
            }

            len = 0; 

            for (here = current->argv[i]; *here; here++) {
                len += *here >= ' ' && *here <= '~' ? 1 : 4;
            }

            if (gvar_92c0 + len <= gvar_92c4 - (i == current->argc - 1 ? 0 : 4) || !gvar_92c8)
                fun_4110(current->argv[i]);
            else {
                // jne 4d90
                out_string("...");
                break;
            }
        }
    }

    if (gvar_9430 != 0) {
        char *str = "\033[0m";
        while (*str) fun_3f90(*str++);
    }

    if (gvar_9440 || gvar_9468 || current->children == NULL) {
        // je 4af0
        while (closing--)
            fun_3f90(']');
         fun_4210();
    }

    if (level >= gvar_9480) {
        if (gvar_9480 == 0) {
            // je 4ce6
            gvar_9480 = 0x64;   // 100
        } 
        else {
            gvar_9480 *= 2;
        }

        if (!(gvar_9478 = realloc(gvar_9478, gvar_9480 * sizeof(int)))) {
            perror("realloc");
            exit(1);
        }

        if (!(gvar_9470 = realloc(gvar_9470, gvar_9480 * sizeof(int)))) {
            perror("realloc");
            exit(1);
        }
    }

    gvar_9470[level] = !last;

    if (gvar_9440 || gvar_9468) {
        // jne 482d
        gvar_9470[level] = swapped + (comm_len > 1 ? 0 : -1);
        count = 0;

        for (walk = current->children; walk; walk = next) {
            next = walk->next;
            if (gvar_92cc && walk->child->flags & 0x2) {
                // jne 4b55
                scan = &walk->next;
                while (*scan) {     // *scan == walk->next
                    if (!fun_4270(walk->child, (*scan)->child)) {
                        // je 4b78
                        scan = &(*scan)->next;    // scan=&walk->next->next
                    }
                    else {
                        if (next == *scan)
                            next = (*scan)->next;
                        first++;
                        tmp_child = (*scan)->next;
                        free(*scan);
                        count = first;
                     }
                }   // while (*scan)

                fun_4340(walk->child, level + 1, count + 1, 0, !next, current->uid, closing+ (count ? 2 : 1));
            }
            else { 
                fun_4340(walk->child, level + 1, 1, 0, !walk->next, current->uid, 0);
            }
        }
        return;
    }

    gvar_9470[level] = comm_len + gvar_92c0 - rep + add;
    if (gvar_92c4 >= gvar_92c0 && gvar_92c8) {
        out_string(shape_pointer->six);
        fun_3f90('+');
        fun_4210();
        return;
    }

    first = 1;
    for (walk = current->children; walk; walk = next) {
        next = walk->next;
        count = 0;  // 4c0a

        if (gvar_92cc) {
            // jne 4bfd
            scan = &walk->next;            
            while (*scan) {     // *scan == walk->next
                if (!fun_4270(walk->child, (*scan)->child)) {
                    // je 4c18
                    scan = &(*scan)->next;      // ==> scan = &walk->next->next;
                }
                else {
                    if (next == *scan)          // *scan = walk->next
                        next = (*scan)->next;
                    tmp_child = (*scan)->next;
                    free(*scan);
                    *scan = tmp_child;
                }
            }
        }

        if (first) {
            // jne 4c75 --> jmpq 47e4
            out_string(next ? shape_pointer->six : shape_pointer->five);
        }

        first = 0;
        fun_4340(walk->child, level + 1, count + 1, walk == current->children, !next, current->uid, closing + (count ? 1 : 0));
    }
}

static void fun_3db0(PROC *r, int id, struct ns_entry **root)
{
    CHILD *walk, *next;
    struct ns_entry *ptr, *last = NULL;
    CHILD *tmp_child, **c;

    if (r == NULL) {
        // je 3ee8
        r = find_proc(1);
        if (!r)
            return;
    }

    if (r->parent == NULL || r->parent->ns[id] != r->ns[id]) {
        // je 3de9

        for (ptr = *root; ptr; ptr = ptr->next) {
            if (ptr->number == r->ns[id])
                break;
            last = ptr;     // ac ????
        }

        if (!ptr) {
            ptr = calloc(0x18, 1);
            if (ptr == NULL) {
                perror("calloc");
                exit(1);
            }
            
            memset(ptr, 0, sizeof(*ptr));   // ac ????
            ptr->number = r->ns[id];
            if (*root == NULL)              // ac ????
                *root = ptr;
            else
                last->next = ptr;
        }

        for (c = &ptr->children; *c; c = &(*c)->next);

        *c = malloc(0x10);
        if (*c == NULL) {
            perror("malloc");
            exit(1);
        }

        (*c)->child = r;
        (*c)->next = NULL;

        if (r->parent) {
            for (c = &r->parent->children; *c; c = &(*c)->next) {                
                if ((*c)->child == r) {
                    tmp_child = (*c)->next;
                    free(*c);
                    // *c = r->parent->children->next;
                    *c = tmp_child;
                    break;
                }
            }
            r->parent = NULL;
        }
    }

    walk = r->children;
    while (walk) {
        next = walk->next;
        fun_3db0(walk->child, id, root);    // walk->child = r->children->child
        walk = next;
    }
}

int get_ws_col()
{
    char *ptr_strtol;
    struct winsize p_0xa8 = {0};
    int col = 0;

    char *p_getenv = getenv("COLUMNS");

    if ((p_getenv != NULL) && (*p_getenv != 0)) {
        col = strtol(p_getenv, &ptr_strtol, 0);
        printf("col = %d\n", col);

        if ( (!*ptr_strtol) && (col > 0) && (col < 0x7ffffffd)) {
            return col;
        }
	}

    if (ioctl(1, 0x5413, &p_0xa8) >= 0) {
        if (p_0xa8.ws_col != 0) {
            return p_0xa8.ws_col;
        }
    }

    return 0x84;
}

static PROC *find_proc(pid_t pid)
{
    PROC *walk;

    for (walk = gvar_9488; walk; walk = walk->next) {
        if (walk->pid == pid)
            return walk;
    }
    return NULL;
}

int fun_4f20(PROC * parent, PROC * child)
{
    CHILD *ac = NULL, **walk = NULL;
    int cmp = 0;

    if (!(ac = (CHILD *)malloc(sizeof(CHILD)))) {
        // je 4fb9
        perror("fun_4f20 malloc");
        exit(1);
    }

    ac->child = child;

    for (walk = &parent->children; *walk; *walk = parent->children->next) {
        if (gvar_9454 != 0) {
            // jne 4f68
            if ((*walk)->child->pid > child->pid) {
                // jg 4fa2
                break;
            }
        }
        else if ((cmp = strcmp((*walk)->child->comm, child->comm)) > 0) {
            break; 
        }
        else if (!cmp && (*walk)->child->uid > child->uid) {
            break;
        }
    }   /* for */

    ac->next = *walk;
    *walk = ac;

    return 0;
}

static PROC *fun_4fd0(const char *comm, pid_t pid, uid_t uid)
{
    PROC * temp = NULL;
    struct stat st;
    char buff[64] = {0};
    int i = 0;

    temp = (PROC*)malloc(sizeof(PROC));
    if (temp == NULL) {
        // je 5131
        perror("malloc");
        exit(1);
    }

    strncpy(temp->comm, comm, 0x42);
    temp->comm[0x41] = '\0';
    temp->pid = pid;
    temp->uid = uid;
    temp->flags = 0;
    temp->argc = 0;
    temp->argv = NULL;
    temp->children = NULL;
    temp->parent = NULL;
    temp->next = gvar_9488;

    for (i = 0; i < 8; i++) {
        sprintf(buff, "/proc/%i/ns/%s", pid, gvar_8ba0[i]);
        if (__xstat(1, buff, &st)) {
            temp->ns[i] = 0;
            continue;
        }
        temp->ns[i] = st.st_ino;         
    }

    gvar_9488 = temp;

    return gvar_9488;
}

int fun_5150(const char *comm, pid_t pid, pid_t ppid, pid_t pgid, uid_t uid,
         const char *args, int size, char isthread, double process_age_sec)  ////
{
    PROC *temp = NULL, *temp_b = NULL;

    for (temp = gvar_9488; temp; temp = temp->next) {
        if (temp->pid == pid) {
            break;
        }
     }

    if (temp == NULL) {
        // jump 53c8
        temp=fun_4fd0(comm, pid, uid);
        // jump 5219
    }   /* if (temp == NULL) */
    else {  /* if (temp != NULL) */
        strncpy(temp->comm, comm, 0x42);
        temp->comm[0x41] = '\0';
        temp->uid = uid;

        if ((gvar_9454 == 0) && (temp->parent != NULL)) {
            PROC *tmp_child = NULL;
            CHILD **walk = NULL;
            for (walk = &temp->parent->children; *walk; walk = &temp->parent->children->next) {

                if ((temp->parent->children->next != NULL) &&
                    (strcmp(temp->parent->children->child->comm, 
                            temp->parent->children->next->child->comm) > 0)) {

                    tmp_child = temp->parent->children->child;
                    temp->parent->children->child = temp->parent->children->next->child;
                    temp->parent->children->next->child = tmp_child;
                }   /* if (temp->parent->children->next != NULL)  */

            }   /* for (; temp->parent->children; temp->parent->children->next) */
        }   /* if ((gvar_9454 == 0) && (temp->parent != NULL)) */
    }   /* if (temp != NULL) */

    if (args != NULL) {
        if (size == 0) {
            // je 53e0
            temp->argc = -1;
            goto goto_5320;
        }

        temp->argc = 0;

        if (size <= 1) 
            goto goto_5320;
        
        int i;
        for (i = 0; i < size - 1; i++) {
            if (!args[i]) {
                temp->argc++;
                while (!args[i] && (i < size -1 ))
                    i++;
            }   /* if (!args[i]) */
        }   /* for (i = 0; i < size - 1; i++) */

        temp->argv = (char **)malloc(temp->argc << 3);
        if (temp->argv == NULL) {
            perror("argv malloc fail.");
            exit(1);
        }

        int len = strlen(temp->argv[0]);

        temp->argv[0] = malloc(size-(len+1));
        if (temp->argv[0] == NULL ) {
            perror("malloc fail.");
            exit(1);
        }

        char *str_memcpy = NULL;
        str_memcpy = memcpy(temp->argv[0], temp->argv, size);

        for (i = 1; i < temp->argc; i++) {
            len = strlen(str_memcpy);
            temp->argv[i] = str_memcpy + len + 0x1;
        }   /* for (i = 1; i < temp->argv; i++) */
    }   /* if (args != NULL) */

goto_5320:
    if (ppid == pid) {
        ppid = 0;
    }
    
    temp->age = process_age_sec;
    temp->pgid = pgid;

    if (isthread) {
        // jne 5390
        temp->flags |= 0x2;
        // jmp 5348
    }

    for (temp_b = gvar_9488; temp_b; temp_b = temp_b->next) {
        if (temp_b->pid == ppid) {
            break;
        }
    }
    
    if (temp_b == NULL) {
        // je 53f0
        temp_b = fun_4fd0("?", pid, 0);
    }

    if (pid != 0) {
        fun_4f20(temp_b, temp);
        temp->parent = temp_b;
    }

    return 0;
}

/* 360c */
void trim_tree_by_parent(PROC * current)
{
    if (!current)
        return;

    PROC * parent = current->parent;
    CHILD *walk, *next;

    if (!parent)
        return;
    
    walk = parent->children;
    while (walk != NULL) {
        next = walk->next;
        free(walk);
        walk = next;
    }

    parent->children = NULL;
    fun_4f20(parent, current);
    trim_tree_by_parent(parent);
}

int main(int argc, char **argv)
{
    struct option var_option[21]={0};
    int i = 0;
    int ret = -1;
    pid_t pid, highlight = 0;
    int pid_set = 0;
    struct ns_entry *nsroot = NULL;
    struct passwd *pw = NULL;
    int nsid = -1;

    memcpy(var_option, long_options, sizeof(long_options));

    #if 0
	for (i = 0; i < 21; i++) {
		printf("%s\n", long_options[i].name);
		printf("%s %d %d %d\n", var_option[i].name, var_option[i].has_arg, 
                                (int)(long)var_option[i].flag, var_option[i].val);
	}
    #endif

    gvar_92c4 = get_ws_col();

    char *p_3a2b = (char *)"";
	char *p_ret;
	if (ret == 0) {
		p_ret = setlocale(__LC_ALL, p_3a2b);
		printf("ret = %s\n", p_ret);
	}

    p_ret = bindtextdomain("psmisc", "/usr/share/locale");
	printf("ret = %s\n", p_ret);

    textdomain("psmisc");

    if (strncmp("pstree.x11", "pstree", 0xb) == 0)  
        gvar_9450 = 1;

    char * p_nl_ret = nl_langinfo(14);  // p_nl_ret="utf-8"

    char * p_38c0 = "UTF-8";
	if (isatty(1) && (strcmp(p_nl_ret, p_38c0) == 0)) {
        // je 2c0a
        shape_pointer = &s_two;
    }
    else {
        if (isatty(1) != 0 && (getenv("TERM") != 0) && (setupterm(0, 1, 0) == 0) && (tigetstr("acsc") != 0)) {
            // jne 2f5d
            shape_pointer = &s_one;
        }
        else {
           shape_pointer = &s_one;
        }
    }

    char ch = -1;
    char *arg = "aAcC:GhH:nN:pglsStTuUVZ";
    while ((ch = getopt_long(argc, argv, arg, var_option, NULL)) != -1) {
		switch (ch) {
            case 'p':
                gvar_6b20 = 1;

            case 'c':
                gvar_6982 = 0;
                break;

            case 'a':
                gvar_9468 = 1;
                break;
            
            case 'Z':
                gvar_9440= 1;
                break;

            case 'V':
                fun_5460();

            case 'U':
                shape_pointer = &s_two;
                break;
            
            case 'T':
                gvar_9444 = 1;
                break;

            case 'S':
                gvar_944c = 1;
                break;
            
            case 'N':
                for (i = 0; i < 7; i++) {    
                    if (strcmp(gvar_8ba0[i], optarg) == 0) {
                        // je 2b88
                    }
                }

            default:
                fun_3bd0_help();
                break;
            
            case 'H':

            case 'C':
                break;

            case 'A':
                shape_pointer = &s_one;
                break;
            
            case 'G':
                shape_pointer = &s_three;
                break;

            case 'u':
                gvar_9464 = 1;
                break;

            case 't':
                gvar_9448 = 1;
                break;

            case 's':
                gvar_9458 = 1;
                break;

            case 'n':
                gvar_9454 = 1;
                break;
            
            case 'l':
                gvar_92c8 = 0;
                break;

            case 'h':
                break;
            
            case 'g':
                gvar_945c = 1;
                gvar_92cc = 0;
                break;

        }   /* switch ended for getopt_long */
    }

    if (optind == argc - 1) {
        // jump 2fb7        
    }

    if (optind != argc) {
        // jne 2a15
        fun_3bd0_help();
    }

    int buffer_size = 0x2001;
    char * buffer = NULL;
    int var_0x18 = 0;

    gvar_92c4 += 1;
    buffer_size = gvar_92c4;

    if (gvar_9468 == 0) {
        // je 339b
        buffer = NULL;
    }
    else {
        buffer = (char *)malloc(buffer_size);
        if (buffer == NULL) {
            // je 3a3b
            perror("malloc error.");
            exit(1);
        }
    }

    int var_r15d = 1;           // var_r15d = empty

    DIR * pdir = opendir(gvar_61cb);    // open /proc
    if (pdir == NULL) {
        // je 3a25
        perror("opendir error...");
        exit(1);
    }

    struct dirent * dp = NULL;
    char *ptr;
    char *path = NULL;
    FILE *fp = NULL;
    struct stat st;

    while ((dp = readdir(pdir)) != NULL) {
        pid = strtol(dp->d_name, &ptr, 0xa);
        if (*ptr != '\0')
            printf("ptr=%s\n", ptr);

        if ((ptr == dp->d_name) && *ptr != '\0') {
            // je 2ce0
            continue;
        }
        else if ((ptr != dp->d_name) && *ptr == '\0') {
            path = (char *)malloc(strlen(dp->d_name) + 0xf);
            if (path == NULL) {
                // je 3a1b
                perror("path error.");
                exit(1);
            }
            var_r15d = 0;       // ac ????
            sprintf(path, "%s/%d/stat", gvar_61cb, pid);
            printf("path=%s\n", path);

            fp = fopen(path, "r");
            if (fp != NULL) {

                sprintf(path, "%s/%d", gvar_61cb, pid);
                printf("path=%s\n", path);

                if (var_0x18 > 0) {

                }
                
                if (stat(path, &st) < 0) {
                    // js 3a09
                    perror("stat error");
                    exit(1);
                }

                char read_buf[0x2000] = {0};
                int fread_size = 0;
                int pgid = 0, ppid = 0;
                unsigned long long proc_stt_jf = 0;
                char *strchr_ret = NULL, *strrchr_ret = NULL;

                fread_size = fread(read_buf, 1, 0x2000, fp);

                if (ferror(fp) != 0) {
                    // jne 2e82
                }
                else {
                    read_buf[fread_size] = 0;
                    strchr_ret = strchr(read_buf, 0x28);
                    strrchr_ret = strrchr(strchr_ret, 0x29);

                    if (strchr_ret == NULL && strrchr_ret == NULL) {
                        // je 2e82
                    }
                    else {
                        *strrchr_ret = 0;

                        int sscanf_ret = sscanf(strrchr_ret + 2, 
                                "%*c %d %d %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %Lu",
                                &ppid, &pgid, &proc_stt_jf);

                        if (sscanf_ret == 3) {
                            // je 33a9      ===>
                            double sc_clk_tck = sysconf(2);

                            if (gvar_6c70 <= sc_clk_tck) {
                                // jbe 3ab2
                                assert(sc_clk_tck > 0);
                            }

                            FILE *fp2 = fopen("/proc/uptime", "r");
                            if (fp2 == NULL) {
                                // je 3a8b
                                perror("pstree: error opening uptime file\n");
                                exit(1);
                            }

                            /* #define __LC_NUMERIC             1 */
                            char *set_locale = setlocale(__LC_NUMERIC, "C");

                            char fscanf_buf[2047+1] = {0};
                            if (fscanf(fp2, "%2047s", fscanf_buf) == EOF) {
                                perror("uptime");
                            }

                            fclose(fp2);

                            setlocale(__LC_NUMERIC, set_locale);

                            double strtod_ret = strtod(fscanf_buf, NULL);

                            if (proc_stt_jf < 0) {
                                // js 36b7
                            }
                            sc_clk_tck = strtod_ret - proc_stt_jf / sc_clk_tck;
                                ++strchr_ret;

                            if (gvar_9444 == 0)  {  /* handle process threads */
                            
                                // je 36da  ===>
                                char *taskpath = (char *)malloc(strlen(path) + 0xa);
                                if (taskpath == NULL) {
                                    // je 3a1b
                                    exit(2);
                                }

                                sprintf(taskpath, "%s/task", path);
                                printf("taskpath=%s\n", taskpath);

                                DIR *dirptr = opendir(taskpath);
                                if (dirptr != NULL) {
                                    // jne 3773  ===>
                                    struct dirent *p_dirent;
                                    while ((p_dirent = readdir(dirptr)) != NULL) {
                                        char *ptrnull = NULL;
                                        int thread = strtol(p_dirent->d_name, &ptrnull, 10);
                                        if ((thread == pid) || (thread == 0)) {
                                            continue;
                                        }

                                        char *threadname = malloc(0x43);
                                        if (threadname == NULL) {
                                            exit(2);
                                        }

                                        if (gvar_9448 != 0) {
                                            int stat_len = snprintf(NULL, 0, "%s/%d/task/%d/stat", gvar_61cb, pid, thread);

                                            stat_len++;

                                            char *stat_path = malloc(stat_len);
                                            if (stat_path == NULL) {
                                                exit(2);              
                                            }

                                            int nbytes = snprintf(stat_path, stat_len, "%s/%d/task/%d/stat",  gvar_61cb, pid, thread);

                                            if (nbytes < 0 || nbytes >= stat_len) 
                                                perror("get_threadname: snprintf");

                                            FILE *stat_file = NULL;
                                            char stat_readbuf[0x2000] = {0};
                                            char *stat_strchr = NULL, *stat_strrchr = NULL;
                                            if ((stat_file = fopen(stat_path, "r")) != NULL) {
                                                if (fgets(stat_readbuf, 0x2000, stat_file) != NULL) {
                                                    stat_strchr = strchr(stat_readbuf, '(');
                                                    stat_strrchr = strrchr(stat_strchr, ')');
                                                    if (stat_strchr && stat_strrchr) {
                                                        // jne 39c8 ===>
                                                        *stat_strrchr = '\0';
                                                        ++stat_strchr;
                                                        sprintf(threadname, "{%.*s}", 0x43, stat_strchr);
                                                        fclose(stat_file);
                                                        free(stat_path);
                                                        // jmpq 391b  ===>
                                                    }

                                                 }  /* if (fgets(stat_readbuf, 0x2000, stat_file) != NULL) */

                                                 fclose(stat_file);

                                            }   /* if ((stat_file = fopen(stat_path, "r")) != NULL) */
                                            free(stat_path);
                                        }   /* if (gvar_9448 != 0) */
                                        else if (gvar_9448 == 0) {
                                            sprintf(threadname, "{%.*s}", 0x43, strchr_ret);           // r12=threadname
                                        }

                                        if (gvar_9468 == 0) {
                                            // je 3994  ===> jmp 395a
                                            fun_5150(threadname, thread, pid, pgid, st.st_uid, NULL, 0, 1, sc_clk_tck);
                                        }
                                        else {                
                                            fun_5150(threadname, thread, pid, pgid, st.st_uid, threadname, strlen(threadname) + 1, 1, sc_clk_tck);
                                        }   /* if (gvar_9468 == 0) */

                                        free(threadname);

                                    }   /* while ((p_dirent = readdir(dirptr)) != NULL)  end */
                                    closedir(dirptr);
                                }   /* if (dirptr != NULL) */

                                free(taskpath);
                            }   /* if (gvar_9444 == 0) */


                            if (gvar_9468 == 0) {
                                // je 359a
                                fun_5150(strchr_ret, pid, ppid, pgid, st.st_uid, NULL, 0, 0, sc_clk_tck);
                            }
                            else if (gvar_9468 != 0) {   /* handle process */
                            
                                sprintf(path, "%s/%d/cmdline", gvar_61cb, pid);

                                int open_fd = -1;
                                open_fd = open(path, 0);
                                if ( open_fd < 0) {
                                    // js 375e  ===> jmpq   2ce0
                                    fclose(fp);
                                    free(path);
                                    continue;
                                }

                                int read_size = -1;

                                read_size = read(open_fd, buffer, buffer_size);
                                if (read_size < 0) {
                                    // js 3757  ===> jmpq   2ce0
                                    close(open_fd);
                                    fclose(fp);
                                    free(path);
                                    continue;
                                }

                                close(open_fd);

                                if (read_size >= buffer_size) {
                                    read_size--;
                                }

                                if (read_size != 0) {
                                    buffer[read_size++] = 0;
                                }

                                fun_5150(strchr_ret, pid, ppid, pgid, st.st_uid, buffer, read_size, 0, sc_clk_tck);
                            }   /* if (gvar_9468 != 0) */

                        }   /* if (sscanf_ret == 3) */
                    }   /* if (strchr_ret == NULL && strrchr_ret == NULL) */
                }   /* if (ferror(fp) != 0) */

                fclose(fp);

            }   /* if (fp != NULL) */
            free(path);

        }   /* if ((ptr != dp->d_name) && *ptr == '\0') */
    }   /* while ((dp = readdir64(pdir)) != NULL) */    

    closedir(pdir);

    PROC *temp = NULL, *walk = NULL;

    for (temp = gvar_9488; temp; temp = temp->next) {
        if (temp->pid == 1) {
            break;
        }
    }

    if (temp == NULL) {
        // je 3041
        temp = fun_4fd0("?", 1, 0);
    }   /* if (temp == NULL) */

    if (temp != NULL) {
        for (walk = gvar_9488; walk; walk = walk->next) {
            if (walk->pid == 1 || walk->pid == 0)
                continue;
            if (walk->parent == NULL) {
                fun_4f20(temp, walk);
                walk->parent = temp;
            }
        }
    }  /* if (temp != NULL) */

    if (gvar_9468 != 0) {
        // jne 358b
        free(buffer);
    }   /* if (gvar_9468 != 0) */

    if (var_r15d) {
        // jne 3a51
        fprintf(stderr, "%s is empty (not mounted ?)\n", "/proc");
        exit(1);
    }

    PROC *current, *child_proc;

    for (current = find_proc(highlight); current; current = current->parent)
        current->flags |= 0x1;
    
    if(gvar_9458 && pid_set == 1) {
        if ( (child_proc = find_proc(pid)) == NULL) {
          fprintf(stderr, "Process %d not found.\n", pid);
          return 1;
        }
        trim_tree_by_parent(child_proc);

        pid = 1;
    } 

    if (nsid != 0x7) {
        fun_3db0(NULL, nsid, &nsroot);

        struct ns_entry *ns_ptr = nsroot;
        CHILD *c;
        char buff[14];
        char *str = NULL;

        for (; ns_ptr; ns_ptr = ns_ptr->next) {
            snprintf(buff, sizeof(buff), "[%li]\n", (long int)ns_ptr->number);

            str = buff;
            while (*str)
                fun_3f90(*str++);

            for (c = ns_ptr->children; c; c = c->next) {
                fun_4340(c->child, 0, 1, 1, 1, 0, 0);
            }
        }
    }
    else if (pw == 0) {
        // je 3679
        fun_4340(find_proc(pid), 0, 1, 1, 1, 0, 0);
    }
    else {
        // 3327
        fun_4e70(find_proc(1), pw->pw_uid);
        if (!gvar_9438) {
            fprintf(stderr, "No processes found.\n");
            return 1;
        }
    }

    if (gvar_9478 != NULL) {
        free(gvar_9478);
        gvar_9478 = NULL;
    }

    if (gvar_9470 != 0) {
        free(gvar_9470);
        gvar_9470 = NULL;
    }

    gvar_9480 = 0;

    PROC *walk1, *next1;
    CHILD *walk1_child, *next1_child;
    walk1 = gvar_9488;

   while (walk1 != NULL) {
        next1 = walk1->next;
        walk1_child = walk1->children;
        while (walk1_child != NULL) {
            next1_child = walk1_child->next;
            free(walk1_child);
            walk1_child = next1_child;
        };

        if (walk1->argv) {
            free(walk1->argv[0]);
            free(walk1->argv);
        }

        free(walk1);
        walk1 = next1;
    }

    gvar_9488 = NULL;

    struct ns_entry *walk2, *next2;
    walk2 = nsroot;

    while (walk2 != NULL) {
        next2 = walk2->next;
        walk1_child = walk2->children;
        while (walk1_child != NULL) {
            next1_child = walk1_child->next;
            free(walk1_child);
            walk1_child = next1_child;
        }
        free(walk2);
        walk2 = next2;
    }

    nsroot = NULL;

    if (gvar_9450 == 1) {
        fprintf(stderr, "Press return to close\n");
        (void) getchar();
    }

    return 0;
}


#if 0

https://blog.csdn.net/u011011827/article/details/58709139/
https://www.cnblogs.com/zhuangquan/p/11867339.html
https://blog.csdn.net/u010034969/article/details/112236885
https://cloud.tencent.com/developer/article/1704612
https://blog.51cto.com/u_15923385/5971835

https://blog.csdn.net/boonya/article/details/81559678
https://blog.csdn.net/u010034969/article/details/112236885

struct passwd {
    char *pw_name;      // 0x00
    char *pw_passwd;    // 0x08
    int pw_uid;         // 0x10
    int pw_gid;
    char *pw_gecos;
    char *pw_dir;
    char *pw_shell;
};

几种跳转指令和对应的机器码
0xE8    CALL    后面的四个字节是地址
0xE9    JMP    后面的四个字节是偏移
0xEB    JMP    后面的二个字节是偏移
0xFF15    CALL    后面的四个字节是存放地址的地址
0xFF25    JMP    后面的四个字节是存放地址的地址

比如想实现循环跳转当前指令，就可以是eb fe，或者e8 fb ff ff ff

0x68    PUSH    后面的四个字节入栈
0x6A    PUSH    后面的一个字节入栈

shellcode跳转回原始OEP方法一
大部分人比较喜欢直接jmp跳转到原始oep，这时候一般都用e9跳转，e9后面的四个字节是一个偏移地址。
计算公式： 偏移地址 = 目的地址 - 跳转基地址(jmp的下一条指令的地址)
也就是 原始OEP - jmp的下一条指令的地址

db    0e9h        ;这是jmp
OEPOffs:
dd    ?        ;这里是4个字节 未初始化

偏移地址 = 原始OEP - (offset OEPOffs + 4)  为什么+4 因为OEPOffs标号向后偏移4个字节 才是jmp的下一条指令地址  也就是跳转基地址

shellcode跳转回原始OEP方法二
有些人用 push oep然后jmp dword ptr [esp]的方法跳回原始oep，这时候shellcode要这样写：

db    68h
OEP:
dd    ?
jmp dword ptr [esp]

68h是 push后面四个字节的意思  dd ? 声明了四个字节，然后通过OEP标号，定位到这个位置，然后把原始OEP写进去就可以了

#endif
